import { defineComponent, onMounted, PropType, ref } from 'vue';
import { Actions, CategoryOption, Options, ValueOption } from '@/components/Table/types';
import { getQueryCondition, Select, selectLikeWithStatus } from '@/components/Table/hooks/useSelect';
import { ElMessage, ElMessageBox } from 'element-plus';
import { useSearch } from '@/components/Table/hooks/useSearch';
import { getTableOptions, getTableOptionsAsync } from '@/components/Table/hooks/useOptions';
import { usePagination } from '@/components/Table/hooks/usePagination';
import { RowStatus, useTable } from '@/components/Table/hooks/useTable';
import { useStatus } from '@/components/Table/hooks/useStatus';
import { getActions, getActionsFromAuthority } from '@/components/Table/hooks/useActions';
import { ObjectUtil } from '@/utils/ObjectUtil';
import { BaseModel, DataResponse, PageInfo, ReadOnlyModel } from '@/services/core';
import { HttpUtil } from '@/utils/HttpUtil';
import { useLeaveTable } from '@/components/Table/hooks/useLeaveTable';
import { useStore } from 'vuex';
import { DataService } from '@/services/core/DataService';
import { Check, Close, Delete, Edit, Plus, Search } from '@element-plus/icons-vue';

export type TableModel = BaseModel<unknown> & ReadOnlyModel;

export interface ManageTableProps<T extends TableModel, Id = T extends BaseModel<infer U> ? U : number> {
  service: DataService<T, Id>;
  defaultModel: T;
  tableOptions: Options<T>;
  tableActions?: Actions;
  tableName?: string;
  authorities?: string[];
}

export interface ElTable {
  doLayout: () => void;
}

export interface ManageTableInstance<T> {
  select: () => Promise<DataResponse<PageInfo<T>>>;
}

export type TableRow = TableModel & RowStatus;

export const isReadOnly = (
  option: ValueOption<unknown, unknown> | CategoryOption<unknown, unknown>,
  row: TableRow
): boolean => {
  return typeof option.readOnly === 'function'
    ? option.readOnly(row) || row.readOnly || (row.rowStatus !== 1 && row.rowStatus !== 2)
    : option.readOnly || row.readOnly || (row.rowStatus !== 1 && row.rowStatus !== 2);
};

export default defineComponent({
  name: 'ManageTable',
  props: {
    /**
     * @author 戴俊明 <idaijunming@163.com>
     * @description service会调用selectLike、insert、update、deleteById、deleteByIds方法
     * @date 2021/5/23 22:30
     **/
    service: {
      type: Object as PropType<DataService<TableModel, unknown>>,
      required: true,
    },
    defaultModel: {
      type: Object as PropType<TableModel>,
      required: true,
    },
    tableOptions: {
      type: Object as PropType<Options<TableModel>>,
      required: true,
    },
    tableActions: Object as PropType<Actions>,
    tableName: String as PropType<string>,
    authorities: Array as PropType<string[]>,
  },
  setup(props: ManageTableProps<TableModel>) {
    const options = getTableOptions(props.tableOptions);
    let actions;
    if (props.authorities) {
      actions = getActionsFromAuthority(props.authorities, props.tableName);
    } else if (props.tableActions) {
      actions = getActions(props.tableActions);
    } else {
      const store = useStore();
      actions = getActionsFromAuthority(store.getters['account/info']?.authorities, props.tableName);
    }
    const { choice, query, clearQuery, currentChoiceOption } = useSearch<TableModel>(props.defaultModel, options);
    const { getPageNum, pageControl, setCurrent: _setCurrent, setPageSize: _setPageSize } = usePagination();
    const { setSelection, setSort: _setSort, tableControl } = useTable<TableRow>();
    const { insertStatus, resetStatus, statusControl, updateStatus } = useStatus<TableModel>();

    const select: Select<TableModel> = () => {
      return selectLikeWithStatus(
        props.service.selectLike,
        getQueryCondition<TableModel>({ choice, query }, pageControl, tableControl, options),
        pageControl,
        tableControl
      );
    };
    const setCurrent = async (current: number) => {
      if (_setCurrent(current)) {
        try {
          return await select();
        } catch (e) {
          // console.log(e.response);
          ElMessage.error((e as Error).message);
          return null;
        }
      } else {
        return null;
      }
    };
    const setPageSize = async (size: number) => {
      if (_setPageSize(size)) {
        try {
          return await select();
        } catch (e) {
          // console.log(e.response);
          ElMessage.error((e as Error).message);
          return null;
        }
      } else {
        return null;
      }
    };
    const setSort = (column: { prop: string; order: string }) => {
      _setSort(column);
      select().catch(e => {
        ElMessage.error((e as Error).message);
      });
    };

    onMounted(() => {
      getTableOptionsAsync(options).then(() => {
        select().catch(e => {
          ElMessage.error((e as Error).message);
        });
      });
    });

    const elTableRef = ref(undefined as unknown as ElTable);

    const insertRecord = async (record: TableRow) => {
      tableControl.loading = true;
      try {
        const resp = await props.service.insert(record);
        if (HttpUtil.isCreated(resp)) {
          // 数据库插入成功
          ElMessage.success('保存成功！');
        } else {
          // 数据库插入失败，服务器出错
          if (tableControl.tableData.length === 0) {
            pageControl.current -= 1;
          }
          ElMessage.warning('保存失败！');
        }
      } catch (e) {
        if (tableControl.tableData.length === 0) {
          pageControl.current -= 1;
        }
        ElMessage.error((e as Error).message);
      } finally {
        record.rowStatus = 0;
        resetStatus();
        await select();
        tableControl.loading = false;
      }
    };
    const updateRecord = async (record: TableRow) => {
      tableControl.loading = true;
      try {
        const resp = await props.service.update(record);
        if (HttpUtil.isCreated(resp)) {
          // 数据库更新成功
          ElMessage.success('保存成功！');
        } else {
          // 数据库更新失败，服务器出错
          ElMessage.warning('保存失败！');
        }
      } catch (e) {
        ElMessage.error((e as Error).message);
      } finally {
        record.rowStatus = 0;
        resetStatus();
        await select();
        tableControl.loading = false;
      }
    };
    const deleteRecord = async (record: TableRow) => {
      tableControl.loading = true;
      try {
        const resp = await props.service.deleteById(record.id);
        if (HttpUtil.isNoContent(resp)) {
          // 数据库删除成功
          if (tableControl.tableData.length === 1) {
            pageControl.current -= 1;
          }
          ElMessage.success('删除成功！');
        } else {
          // 数据库删除失败
          ElMessage.error('删除失败！');
        }
      } catch (e) {
        ElMessage.error((e as Error).message);
      } finally {
        await select();
        tableControl.loading = false;
      }
    };
    const deleteRecords = async (records: Array<TableRow>) => {
      tableControl.loading = true;
      try {
        const resp = await props.service.deleteByIds(records.map(record => record.id));
        if (HttpUtil.isNoContent(resp)) {
          // 数据库删除成功
          if (tableControl.tableData.length === records.length) {
            pageControl.current -= 1;
          }
          ElMessage.success('删除成功!');
        } else {
          // 数据库删除失败
          ElMessage.error('删除失败!');
        }
      } catch (e) {
        ElMessage.error((e as Error).message);
      } finally {
        await select();
        tableControl.loading = false;
      }
    };

    const handleInsertCommand = () => {
      setCurrent(getPageNum(pageControl.total + 1)).then(() => {
        const row = ObjectUtil.clone(props.defaultModel) as TableRow;
        row.rowStatus = 1;
        // console.log(tableControl.tableData);
        // tableControl.tableData.push(reactive(row));
        tableControl.tableData = [...tableControl.tableData, row];
        insertStatus(row);
        // elTableRef.value.doLayout();
      });
    };
    const handleUpdateCommand = (row: TableRow) => {
      if (row.readOnly) {
        ElMessage.warning('只读数据，无法更改！');
      } else {
        row.rowStatus = 2;
        const record = ObjectUtil.clone(row);
        updateStatus(record);
      }
    };
    const handleSaveSure = (row: TableRow) => {
      // console.log(row);
      // console.log(statusControl.data);
      if (ObjectUtil.equals(statusControl.data as TableRow, row, ['rowStatus'])) {
        if (statusControl.status === 1) {
          // 没有填写信息
          ElMessage.warning('未填写有效信息！');
          row.rowStatus = 0;
          tableControl.tableData.pop();
          resetStatus();
          if (tableControl.tableData.length === 0) {
            pageControl.current -= 1;
            select().catch(e => {
              ElMessage.error((e as Error).message);
            });
          }
        } else {
          // 没有修改
          row.rowStatus = 0;
          resetStatus();
          ElMessage.success('未修改！');
        }
      } else {
        if (statusControl.status === 1) {
          insertRecord(row).catch(e => {
            ElMessage.error((e as Error).message);
          });
        } else {
          updateRecord(row).catch(e => {
            ElMessage.error((e as Error).message);
          });
        }
      }
    };
    const handleSaveClose = (row: TableRow) => {
      if (row.rowStatus === 1) {
        tableControl.tableData.pop();
        resetStatus();
        if (tableControl.tableData.length === 0) {
          pageControl.current -= 1;
          select().catch(e => {
            ElMessage.error((e as Error).message);
          });
        }
      } else if (row.rowStatus === 2) {
        Object.assign(row, statusControl.data);
        row.rowStatus = 0;
        resetStatus();
      }
    };
    const handleDeleteCommand = async (row: TableRow) => {
      if (row.readOnly) {
        ElMessage.warning('正在删除只读数据！');
      } else {
        try {
          await ElMessageBox.confirm('此操作将删除该记录, 是否继续?', '警告', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning',
          });
        } catch (e) {
          return;
        }
        await deleteRecord(row);
      }
    };
    const handleBatchDeleteCommand = async () => {
      if (tableControl.selection) {
        if (tableControl.selection.some(row => row.readOnly)) {
          ElMessage.warning('无法删除只读数据！');
        } else {
          try {
            await ElMessageBox.confirm(`此操作将删除 ${tableControl.selection.length} 条记录, 是否继续?`, '警告', {
              confirmButtonText: '确定',
              cancelButtonText: '取消',
              type: 'warning',
            });
          } catch (e) {
            return;
          }
          await deleteRecords(tableControl.selection as TableRow[]);
        }
      } else {
        ElMessage.warning('没有选择项！');
      }
    };

    useLeaveTable(statusControl, handleSaveClose);
    return {
      choice,
      query,
      pageControl,
      tableControl,
      statusControl,
      options,
      actions,
      elTableRef,
      select,
      clearQuery,
      currentChoiceOption,
      setSort,
      setSelection,
      handleInsertCommand,
      handleUpdateCommand,
      handleSaveSure,
      handleSaveClose,
      handleDeleteCommand,
      handleBatchDeleteCommand,
      setCurrent,
      setPageSize,
      isReadOnly,
      icons: {
        Search,
        Plus,
        Delete,
        Edit,
        Check,
        Close,
      },
    };
  },
});
